import 'package:day_demo/src/logger_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:rxdart/rxdart.dart';

class ItemContext {
  ItemContext({
    required this.context,
    required this.id,
  });
  final BuildContext context;
  final int id;

  @override
  int get hashCode => Object.hashAll([id]);

  @override
  bool operator ==(Object other) {
    return identical(this, other) || other is ItemContext && other.id == id;
  }
}

class VisiblePage extends StatefulWidget {
  const VisiblePage({super.key});

  @override
  State<VisiblePage> createState() {
    return _VisiblePageState();
  }
}

class _VisiblePageState extends State<VisiblePage> {
  late Set<ItemContext> _itemsContexts;

  late BehaviorSubject<ScrollNotification> _streamController;
  double position = 0.0;

  double sensitivityFactor = 1.0;
  @override
  void initState() {
    super.initState();
    _itemsContexts = <ItemContext>{};
    _streamController = BehaviorSubject<ScrollNotification>();
    _streamController
        .bufferTime(const Duration(milliseconds: 100))
        .where((event) => event.isNotEmpty)
        .listen((event) {
      _onScroll(event);
    });
  }

  @override
  void dispose() {
    _itemsContexts.clear();
    _streamController.close();
    super.dispose();
  }

  void _onScroll(List<ScrollNotification> notifications) {
    // LogHelper.d(notifications.last.metrics.pixels);
    for (var item in _itemsContexts) {
      if (!item.context.mounted) {
        continue;
      }
      final RenderObject? object = item.context.findRenderObject();
      if (object == null || !object.attached) {
        continue;
      }
      final RenderAbstractViewport viewport = RenderAbstractViewport.of(object);
      final double vpHeight = viewport.paintBounds.height;
      final ScrollableState scrollableState = Scrollable.of(item.context);
      final ScrollPosition scrollPosition = scrollableState.position;
      final RevealedOffset vpOffset = viewport.getOffsetToReveal(object, 0);
      final Size size = object.semanticBounds.size;
      final double deltaTop = vpOffset.offset - scrollPosition.pixels;
      final double deltaBottom = deltaTop + size.height;
      bool isInViewport = false;

      isInViewport = (deltaTop >= 0.0 && deltaTop < vpHeight);
      if (!isInViewport) {
        isInViewport = (deltaBottom > 0.0 && deltaBottom < vpHeight);
      }
      // LogHelper.d('${item.id} $isInViewport');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(30),
        child: SizedBox(
          width: 200.0,
          height: 300.0,
          child: Container(
            color: Colors.red,
            child: NotificationListener<ScrollNotification>(
              onNotification: (ScrollNotification scrollNotification) {
                if (scrollNotification.metrics.pixels - position >=
                    sensitivityFactor) {
                  print('Axis Scroll Direction : Up');
                  position = scrollNotification.metrics.pixels;
                }
                if (position - scrollNotification.metrics.pixels >=
                    sensitivityFactor) {
                  print('Axis Scroll Direction : Down');
                  position = scrollNotification.metrics.pixels;
                }
                if (!_streamController.isClosed) {
                  _streamController.add(scrollNotification);
                }
                return true;
              },
              child: ListView.builder(itemBuilder: (ctx, index) {
                return _buildItem(index);
              }),
            ),
          ),
        ),
      ),
    );
  }

  Widget _buildItem(int index) {
    return LayoutBuilder(builder: (ctx, _) {
      _itemsContexts.add(ItemContext(context: ctx, id: index));
      return ListViewItem(itemIndex: index);
    });
  }
}

class ListViewItem extends StatelessWidget {
  const ListViewItem({
    super.key,
    required this.itemIndex,
  });
  final int itemIndex;
  @override
  Widget build(BuildContext context) {
    return Card(
      child: Container(
        width: 100,
        height: 100,
        color: Colors.orange,
        child: Center(
          child: Text(itemIndex.toString()),
        ),
      ),
    );
  }
}
